package com.xuecheng.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.xuecheng.commons.model.dto.CoursePubIndexDto;
import com.xuecheng.commons.model.dto.PageRequest;
import com.xuecheng.commons.model.vo.CoursePubIndexVo;
import com.xuecheng.commons.model.vo.CoursePubVo;
import com.xuecheng.commons.model.vo.PageResponseResult;
import com.xuecheng.commons.model.vo.ResponseResult;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.api.ContentClient;
import com.xuecheng.search.domain.CoursePubIndex;
import com.xuecheng.search.service.SearchService;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@Service
public class SearchServiceImpl implements SearchService  {

    @Autowired
    RestHighLevelClient restHighLevelClient;

    @Autowired
    ContentClient contentClient;

    //根据课程发布id，创建es索引
    @Override
    public void createIndex(Long coursePubId) throws IOException {
        //1.根据课程发布id，查询课程发布对象
        ResponseResult<CoursePubVo> result = contentClient.findById(coursePubId);
        CoursePubVo vo = result.getData();
        if (vo != null) {
            //2.调用es的api保存数据
            //2.1 创建IndexRequest
            IndexRequest request = new IndexRequest("course");
            //2.2 设置数据和id
            request.id(vo.getId().toString());
            request.source(JSON.toJSONString(vo), XContentType.JSON);
            //2.3 调用RestClient对象保存
            restHighLevelClient.index(request,RequestOptions.DEFAULT);
        }
    }

    //删除es索引
    @Override
    public void deleteIndex(Long coursePubId) throws Exception {
        DeleteRequest request = new DeleteRequest("course",coursePubId.toString());
        restHighLevelClient.delete(request,RequestOptions.DEFAULT);
    }

    //条件查询
    @Override
    public ResponseResult search(PageRequest request, CoursePubIndexDto dto) throws Exception {
        //1.创建SearchRequest
        SearchRequest searchRequest = new SearchRequest("course");
        //2.调用方法，创建SearchSourceBuilder对象(查询设置:条件，分页，高亮)
        //构建builder
        searchRequest.source(generatorBuilder(request,dto));
        //3.调用RestClient方法，发送请求，获取响应
        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        return parseResponse(response);
    }


    //设置查询参数
    private SearchSourceBuilder generatorBuilder(PageRequest request, CoursePubIndexDto dto) {
        //创建SearchSourceBuilder
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //设置查询条件
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //向boolQuery中设置查询条件,如果参数为空则查询全部
        if (StringUtils.isEmpty(dto.getKeyword())) {
            boolQuery.must(QueryBuilders.matchAllQuery());
        } else {
            boolQuery.must(QueryBuilders.matchQuery("all",dto.getKeyword()));
        }
        //构造筛选条件
        //大分类
        if (!StringUtils.isEmpty(dto.getMt())) {
            boolQuery.filter(QueryBuilders.termQuery("mt",dto.getMt()));
        }
        //小分类
        if (!StringUtils.isEmpty(dto.getSt())) {
            boolQuery.filter(QueryBuilders.termQuery("st",dto.getSt()));
        }
        //难度等级
        if (!StringUtils.isEmpty(dto.getSt())) {
            boolQuery.filter(QueryBuilders.termQuery("grade",dto.getGrade()));
        }
        builder.query(boolQuery);
        //设置分页
        builder.from((request.getPageNo() - 1) * request.getPageSize());  //公式
        builder.size(request.getPageSize());
        //设置高亮
        HighlightBuilder hb = new HighlightBuilder();
        hb.preTags("<font color=gold>")
                .postTags("</font>")
                .field("name")
                .requireFieldMatch(false);
        builder.highlighter(hb);
        return builder;
    }

    //设置响应结果
    private ResponseResult parseResponse(SearchResponse response) {
        //获取总数
        SearchHits hits = response.getHits();
        Long total = hits.getTotalHits().value;  //总数
        //获取数据列表
        //根据SearchHits获取hits数组
        SearchHit[] hitsHits = hits.getHits();
        //循环hits数组
        List<CoursePubIndexVo> vos = new ArrayList<>();
        for (SearchHit hitsHit : hitsHits) {
            //原始数据
            //获取每个hit中的source数据
            String json = hitsHit.getSourceAsString();
            //将source字符串转化为java对象
            CoursePubIndex coursePubIndex = JSON.parseObject(json, CoursePubIndex.class);
            //转化vo
            CoursePubIndexVo vo = BeanHelper.copyProperties(coursePubIndex, CoursePubIndexVo.class);
            //单独设置vo中的indexId参数
            vo.setIndexId(coursePubIndex.getId());

            //解析高亮部分的数据内容
            //获取高亮数据
            Map<String, HighlightField> map = hitsHit.getHighlightFields();
            if (map != null && map.containsKey("name")) {
                //根据name属性过去高亮内容
                HighlightField highlightField = map.get("name");
                String name = highlightField.fragments()[0].toString();
                //设置到原始数据的name属性中
                vo.setName(name);
            }
            vos.add(vo);
        }
        return PageResponseResult.okResult(total,vos);
    }

    //根据id查询es中的数据
    @Override
    public ResponseResult findById(Long id) throws IOException {
        //创建个面具id查询的请求对象 GetRequest
        GetRequest request = new GetRequest("course",id.toString());
        //发送请求
        GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
        //解析_source响应数据
        String json = response.getSourceAsString();
        CoursePubIndex index = JSON.parseObject(json, CoursePubIndex.class);
        //转化vo
        CoursePubIndexVo vo = BeanHelper.copyProperties(index, CoursePubIndexVo.class);
        vo.setIndexId(index.getId());
        return PageResponseResult.okResult(vo);
    }


}
